package il.technion.cs236369.webserver;

import il.technion.cs236369.exceptions.BaseDirDoesntExist;
import il.technion.cs236369.exceptions.SameExtensionDifferentHandler;
import il.technion.cs236369.exceptions.WelcomeFileDoesntExist;

import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * WebServer Configuration. Contains the relevant WebServer configuration for
 * later use.
 * 
 * @author gil
 */
public class WebServerConfiguration {
	private static WebServerConfiguration		_instance	= null;

	private int									_port;
	private String								_baseDirName;
	private String								_welcomeFileName;
	private File								_welcomeFile;
	private File								_baseDir;
	private Map<String, String>					_mimeMap;
	private Map<String, TypeHandlerContainer>	_specificHandlersMap;

	/**
	 * @return the WebServerConfiguration Singleton
	 * @throws IllegalStateException If the configuration has not been initiated
	 */
	public static WebServerConfiguration getInstance() {
		if (_instance == null) {
			throw new IllegalStateException("not initialized");
		}
		return _instance;
	}

	private WebServerConfiguration(int port, String baseDirName, String welcomeFileName) throws BaseDirDoesntExist, WelcomeFileDoesntExist {
		super();

		_port = port;
		_baseDirName = baseDirName;
		_welcomeFileName = welcomeFileName;
		_baseDir = new File(_baseDirName);
		_welcomeFile = new File(_baseDir, _welcomeFileName);
		if (!_baseDir.exists() || !_baseDir.isDirectory()) {
			throw new BaseDirDoesntExist();
		}
		if (!_welcomeFile.exists() || !_welcomeFile.isFile()) {
			throw new WelcomeFileDoesntExist();
		}
		_mimeMap = new HashMap<>();
		_specificHandlersMap = new HashMap<>();
	}

	/**
	 * Initialized a new webserver configuration.
	 * 
	 * @param port The webserver's port.
	 * @param baseDir The webserver's base direcotry.
	 * @param welcomeFile The webserver's welcome file, within the base
	 *            directory.
	 * @throws BaseDirDoesntExist If base directory doesn't exist.
	 * @throws WelcomeFileDoesntExist If welcome file doesn't exist.
	 */
	public static void init(int port, String baseDir, String welcomeFile) throws BaseDirDoesntExist, WelcomeFileDoesntExist {
		if (_instance != null) {
			throw new IllegalStateException("already initialized");
		}

		_instance = new WebServerConfiguration(port, baseDir, welcomeFile);

	}

	private WebServerConfiguration() {
	}

	/**
	 * @return the _port
	 */
	public int getPort() {
		return _port;
	}

	/**
	 * @return the _baseDirName
	 */
	public String getBaseDirName() {
		return _baseDirName;
	}

	/**
	 * @return the _welcomeFile
	 */
	public File getWelcomeFile() {
		return _welcomeFile;
	}

	/**
	 * Gets the MIME for a given extension (Content-Type). If no MIME defined
	 * for the given extension, returns null.
	 * 
	 * @return the MIME for the given extension
	 */
	public String getMime(String extension) {
		return _mimeMap.get(extension.toLowerCase());
	}

	/**
	 * Gets a specific type handler for a given extension. If no type handler
	 * specified for that extension, returns null.
	 * 
	 * @return the type handler for the given extension
	 */
	public TypeHandlerContainer getSpecificHandler(String extension) {
		return _specificHandlersMap.get(extension);
	}

	/**
	 * Sets the MIME definitions
	 * 
	 * @param mimeMap map from extension to content-type
	 */
	public void setAllMimes(Map<String, String> mimeMap) {
		_mimeMap.clear();
		_mimeMap.putAll(mimeMap);
	}

	/**
	 * Sets an handler for each special extension
	 * 
	 * @param handlers Collection of special handlers
	 * @throws SameExtensionDifferentHandler when found two different handlers
	 *             for an extension
	 */
	public void setHandlers(Collection<TypeHandlerContainer> handlers) throws SameExtensionDifferentHandler {
		for (TypeHandlerContainer thc : handlers) {
			for (String extension : thc.getExtensions()) {
				if (_specificHandlersMap.containsKey(extension)) {
					if (!_specificHandlersMap.get(extension).equals(thc)) {
						throw new SameExtensionDifferentHandler();
					}
				}
				_specificHandlersMap.put(extension, thc);
			}
		}
	}
}
